package com.mathdroid.gui.profile;

import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComboBox;

import com.mathdroid.gui.ImageLoader;
import com.mathdroid.gui.main.DroidComboBoxModel;
import com.mathdroid.gui.main.Popup;
import com.mathdroid.model.Model;
import com.mathdroid.model.Profile;
import com.mathdroid.model.Profiles;
import com.mathdroid.persistence.Serializer;

/**
 * This is a popup to open a saved profile.
 */
public class OpenProfile extends Popup {
	/**
	 * Default UID.
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Serializer.
	 */
	private final Serializer s = new Serializer();
	
	/**
	 * Button to close the popup.
	 */
	private final JButton close = new JButton("Close");
	
	/**
	 * Button to open a profile.
	 */
	private final JButton openProfile = new JButton("Open");
	
	/**
	 * Button to create a new profile.
	 */
	private final JButton newProfile = new JButton("New");
	
	/**
	 * Button to delete a profile.
	 */
	private final JButton deleteProfile = new JButton("Delete");
	
	/**
	 * The profiles in a combo box.
	 */
	private JComboBox comboBox = null;
	
	/**
	 * The spacing between components.
	 */
	private static final int SPACING = 10;
	
	/**
	 * The columns of the grid.
	 */
	private static final int GRID_WIDTH = 4;
	
	/**
	 * The image loader.
	 */
	private final ImageLoader il = new ImageLoader();

	/**
	 * Create a new popup to open a profile.
	 * @param parent The parent UI component to align to.
	 */
	public OpenProfile(final Component parent) {
		super(parent);
		final Profiles profiles = this.s.getProfiles();
		DroidComboBoxModel model = new DroidComboBoxModel();
		
		for (Profile p : profiles.values()) {
			model.addElement(p);
		}
	
		this.comboBox = new JComboBox(model);
		
		if (comboBox.getItemCount() > 0) {
			comboBox.setSelectedIndex(0);
		} else {
			comboBox.setSelectedIndex(-1);
		}
		
		this.addDeleteListener(profiles);
		this.addNewProfileListener(parent);
		this.addCloseListener();	
		this.addOpenProfileListener();
		
		this.buildComboBox();
		this.buildOpenProfileButton();
		this.buildNewProfileButton();
		this.buildDeleteProfileButton();
		this.buildCloseButton();
		
		this.pack();
		this.setVisible(true);
	}

	/**
	 * Build the close button.
	 */
	private void buildCloseButton() {
		this.getConstraints().gridx = 3;
		close.setIcon(this.il.getImage("cross"));
		this.getPanel().add(close, this.getConstraints());
	}

	/**
	 * Build the delete button.
	 */
	private void buildDeleteProfileButton() {
		this.getConstraints().gridx = 2;
		deleteProfile.setIcon(this.il.getImage("delete"));
		this.getPanel().add(deleteProfile, this.getConstraints());
	}

	/**
	 * Build the new profile button.
	 */
	private void buildNewProfileButton() {
		this.getConstraints().gridx = 1;
		newProfile.setIcon(this.il.getImage("add"));
		this.getPanel().add(newProfile, this.getConstraints());
	}

	/**
	 * Build the open profile button.
	 */
	private void buildOpenProfileButton() {
		this.getConstraints().insets = new Insets(0, SPACING, SPACING, SPACING);
		this.getConstraints().gridx = 0;
		this.getConstraints().gridy = 1;
		this.getConstraints().fill = GridBagConstraints.HORIZONTAL;
		this.getConstraints().gridwidth = 1;
		this.getConstraints().weightx = 1;
		openProfile.setIcon(this.il.getImage("accept"));
		this.getPanel().add(openProfile, this.getConstraints());
	}

	/**
	 * Build the profiles combo box.
	 */
	private void buildComboBox() {
		this.getConstraints().insets = new Insets(
				SPACING, SPACING, SPACING, SPACING);
		this.getConstraints().gridx = 0;
		this.getConstraints().gridy = 0;
		this.getConstraints().fill = GridBagConstraints.HORIZONTAL;
		this.getConstraints().gridwidth = GRID_WIDTH;
		this.getConstraints().weightx = 1;
		this.getPanel().add(comboBox, this.getConstraints());
	}

	/**
	 * Adds an action listener to the open profile button.
	 */
	private void addOpenProfileListener() {
		openProfile.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				Profile profile = (Profile) comboBox.getSelectedItem();
				
				/* Unregister the model observers that are in the profile */
				Model.unregisterObserver(Model.getProfile().getClassModule());
				
				/* Set the new Profile */
				Model.setProfile(profile);
				
				/* Register the new observers */
				Model.registerObserver(profile.getClassModule());
				Model.refreshItemBrowserModel();
				
				dispose();
			}
		});
	}

	/**
	 * Adds an action listener to the new profile button. It opens a "New 
	 * Profile" popup.
	 * @param parent Parent component.
	 */
	private void addNewProfileListener(final Component parent) {
		newProfile.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				new NewProfile(parent);
				dispose();
			}
		});
	}

	/**
	 * Adds an action listener to the delete button. It deletes the selected
	 * profile.
	 * @param profiles The profiles model.
	 */
	private void addDeleteListener(final Profiles profiles) {
		deleteProfile.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				if (comboBox.getItemCount() > 0) {
					Profile p = (Profile) comboBox.getSelectedItem();
					comboBox.removeItem(p);
					profiles.remove(p.getName());
					s.serialize(profiles);
					
					if (comboBox.getItemCount() > 0) {
						comboBox.setSelectedIndex(0);
					} else {
						comboBox.setSelectedIndex(-1);
						openProfile.setEnabled(false);
						deleteProfile.setEnabled(false);
					}
				}
			}
		});
	}

	/**
	 * Adds an action listener to the close button.
	 */
	private void addCloseListener() {
		this.close.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				dispose();
			}
		});
	}
}
